use async_graphql::SimpleObject;
use linera_sdk::linera_base_types::{AccountOwner, Amount, ChainId};
use serde::{Deserialize, Serialize};

use rfq::TokenPair;

use crate::state::{
    AwaitingTokens, ExchangeInProgress, QuoteProvided, QuoteRequested, RequestState,
};

#[derive(Clone, Debug, Serialize, Deserialize, SimpleObject)]
pub struct RequestData {
    pub(crate) state: RequestState,
}

#[allow(dead_code)]
impl RequestData {
    pub fn update_state_with_quote(&mut self, quote: Amount, quoter_owner: AccountOwner) {
        match &self.state {
            RequestState::QuoteRequested(QuoteRequested { token_pair, amount }) => {
                self.state = RequestState::QuoteProvided(QuoteProvided {
                    token_pair: token_pair.clone(),
                    amount: *amount,
                    amount_offered: quote,
                    quoter_owner,
                });
            }
            _ => panic!("Request not in the QuoteRequested state!"),
        }
    }

    pub fn quote_provided(&self) -> QuoteProvided {
        match &self.state {
            RequestState::QuoteProvided(quote_provided) => quote_provided.clone(),
            _ => panic!("Request not in the QuoteProvided state!"),
        }
    }

    pub fn start_exchange(&mut self, temp_chain_id: ChainId) {
        match &self.state {
            RequestState::QuoteProvided(_) | RequestState::AwaitingTokens(_) => {
                self.state = RequestState::ExchangeInProgress(ExchangeInProgress { temp_chain_id });
            }
            _ => panic!("Request not in the QuoteProvided or AwaitingTokens state!"),
        }
    }

    pub fn accept_quote(&mut self, temp_chain_id: ChainId) {
        match &self.state {
            RequestState::QuoteProvided(QuoteProvided {
                token_pair,
                amount_offered,
                quoter_owner,
                ..
            }) => {
                self.state = RequestState::AwaitingTokens(Box::new(AwaitingTokens {
                    token_pair: token_pair.clone(),
                    amount_offered: *amount_offered,
                    quoter_account: *quoter_owner,
                    temp_chain_id,
                }));
            }
            _ => panic!("Request not in the QuoteProvided state!"),
        }
    }

    pub fn awaiting_tokens(&self) -> AwaitingTokens {
        match &self.state {
            RequestState::AwaitingTokens(awaiting_tokens) => (**awaiting_tokens).clone(),
            _ => panic!("Request not in the AwaitingTokens state!"),
        }
    }

    pub fn token_pair(&self) -> TokenPair {
        self.state.token_pair()
    }
}
